package semantic_compute.common.yago_helper;

import com.orientechnologies.orient.core.db.record.OTrackedList;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.orient.OrientElementIterable;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
import common.dao.orient.OrientGraphDao;
import common.dao.orient.OrientJDBCDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import semantic_compute.common.yago_schema.LuceneItem;
import sun.security.pkcs11.P11Util;

import java.sql.Connection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by julianzliu on 4/21/2017.
 */
public class YagoLuceneQueryer {

    static final Logger logger = LoggerFactory.getLogger(YagoLuceneQueryer.class);

    private OrientJDBCDao orientJDBCDao;
    private Connection connection;

    private OrientGraphDao orientGraphDao;
    private OrientGraph orientGraph;

    public YagoLuceneQueryer(){
        this.orientJDBCDao = new OrientJDBCDao();
        this.connection  =this.orientJDBCDao.getConn();

        this.orientGraphDao = new OrientGraphDao();
        this.orientGraph = this.orientGraphDao.getGraph();
    }




    public void testQueryOrientDbWithDiffentLang(String phrase){
        String[] phrases = phrase.split(" ");
        String query = "+eng";
        for(String token: phrases){
            query += " +" + token;
        }
        /*
        String sql = String.format(
                             "select in.@rid as rid, in.yago_id as yid, max(lucene_score) as max_score from (" + "\n"
                        +       "select lucene_score,in() from ("  + "\n"
                        +          "select *,$score as lucene_score"  + "\n"
                        +          "from YAGO_LABEL_CLASS"  + "\n"
                        +          "where yago_label LUCENE \"%s\""  + "\n"
                        +        ")"  + "\n"
                        +    ")"  + "\n"
                        +    "where in.yago_type='CONCEPT'"  + "\n"
                        +    "group by in order by max_score desc;"  + "\n"
                , query
        );
        */
        // 上述查询有问题，暂且保留


        /*
        Statement stmt = null;
        ResultSet rs = null;
        List< Pair<String, Double >> sortedList = new ArrayList<>();
        try{
            stmt = this.connection.createStatement();
            rs = stmt.executeQuery(sql);
            while (rs.next()){

                Array rids = rs.getArray("rid");//rs.getString("rid");
                ResultSet ridsResultSet = rids.getResultSet();
                String rid = null;
                if(ridsResultSet.next()) rid = ridsResultSet.getString("0");
                //Array yids = rs.getArray("yid");
                Double score = rs.getDouble("max_score");
                System.out.println(String.format("[rid = %s, yid = %s, score = %f]", rid, score));
            }
            rs.close();
            stmt.close();

        }catch (Exception e) {
            e.printStackTrace();
        }
        */


        String sql = String.format(
                "select in.@rid as rid, in.yago_id as yid, lucene_score as max_score from (" + "\n"
                        +       "select lucene_score,in() from ("  + "\n"
                        +          "select *,$score as lucene_score"  + "\n"
                        +          "from YAGO_LABEL_CLASS"  + "\n"
                        +          "where yago_label LUCENE \"%s\""  + "\n"
                        +        ")"  + "\n"
                        +    ")"  + "\n"
                        +    "where in.yago_type='CONCEPT'"  + "\n"
                , query
        );

        logger.info("[getLuceneSortedResultForConcept] sql = \n{}" , sql);

        /*
        1) 上述查询的结果为  ( {yago_concept} -->LABEL-->  yago_label  -->LUCENE-->  "phrase"  )
        2) 需要将第一列和第二列的集合展开
        3）有没有办法直接生成展开后的集合，同时每一行附带展开前的 score 值？？？
         */

        /*
        http://orientdb.com/javadoc/latest/com/orientechnologies/orient/core/sql/OCommandSQL.html
         */

        Iterable<Vertex> vertices = (Iterable<Vertex>) this.orientGraph.command(
                new OCommandSQL(sql )
        ).execute();

        for(Vertex row: vertices){
            for(String key : row.getPropertyKeys()){
                System.out.println("  " + key);
            }
            Float score = (Float)row.getProperty("max_score");
            OTrackedList yid_list = row.getProperty("yid");
            OrientElementIterable rid_list = row.getProperty("rid");
            Iterator iterator = rid_list.iterator();
            while(iterator.hasNext()){
                Vertex rid = (Vertex)iterator.next();
                System.out.println("  rid="+rid.getProperty("rid"));
                for(String key:rid.getPropertyKeys()){
                    System.out.println("      key="+key);
                }
            }
            System.out.println("  score = " + score + " rids = " + row.getProperty("rid") + " yids = " + row.getProperty("yid"));
            System.out.println("  score = " + score + " rids = " + row.getProperty("rid").getClass() + " yids = " + row.getProperty("yid").getClass());

        }


    }





    /************************************************************
     *  返回每个 yago_id 的匹配分值
     */
    public Map<String, Float> getLuceneSortedResultWrong(String phrase){
        String[] phrases = phrase.split(" ");
        String query = "+eng";
        for(String token: phrases){
            query += " +" + token;
        }
        logger.info("[getLuceneSortedResultForConcept] query_string = {}", query);
        String sql = String.format(
                "select in.@rid as rid, in.yago_id as yid, lucene_score as max_score from (" + "\n"
                        +       "select lucene_score,in() from ("  + "\n"
                        +          "select *,$score as lucene_score"  + "\n"
                        +          "from YAGO_LABEL_CLASS"  + "\n"
                        +          "where yago_label LUCENE \"%s\""  + "\n"
                        +        ")"  + "\n"
                        +    ")"  + "\n"
                        +    "where in.yago_type='CONCEPT'"  + "\n"
                , query
        );
        logger.info("[getLuceneSortedResultForConcept] sql = \n{}" , sql);
        Iterable<Vertex> vertices = (Iterable<Vertex>) this.orientGraph.command(
                new OCommandSQL(sql )
        ).execute();
        Map<String, Float>  yago_concept_maxscore = new HashMap<>();
        for(Vertex row: vertices){
            Float score = (Float)row.getProperty("max_score");
            System.out.println("score=" + score);
            OTrackedList yid_list = row.getProperty("yid");
            Iterator iterator = yid_list.iterator();
            while(iterator.hasNext()){
                String yago_id = (String)iterator.next();
                System.out.println("  yago_id=" + yago_id);
                if(!yago_concept_maxscore.containsKey(yago_id)){
                    yago_concept_maxscore.put(yago_id, score);
                }
                else {
                    if(yago_concept_maxscore.get(yago_id) < score){
                        yago_concept_maxscore.put(yago_id, score);
                    }
                }
            }
        }
        return yago_concept_maxscore;

    }








    /************************************************************
     *  返回每个 Label 与 Phrase 的匹配分值
     */
    public Map<String, LuceneItem> getLuceneSortedResultForConcept(String phrase) {
        String query = YagoQueryHelper.phraseToQuery(phrase);
        String sql = String.format(
                "select @rid as rid,$score as score, yago_label.length() as length from YAGO_LABEL_CLASS where yago_label LUCENE \"%s\"", query
        );

        logger.info("[getLuceneSortedResultForConcept] sql = \n{}" , sql);
        Iterable<Vertex> vertices = (Iterable<Vertex>) this.orientGraph.command(
                new OCommandSQL(sql )
        ).execute();

        Map<String, LuceneItem> lucene_scores = new HashMap<>();
        for(Vertex row: vertices){
            String rid = YagoQueryHelper.getRidOfVertex( row.getProperty("rid") );
            lucene_scores.put( rid, new LuceneItem(rid,row.getProperty("score"),row.getProperty("length") ));
        }

        return lucene_scores;
    }


    /************************************************************
     *  返回每个 Label 与 Phrase 的匹配分值
     */
    public Map<String, LuceneItem> getLuceneSortedResultForEntity(String phrase) {
        String query = YagoQueryHelper.phraseToQuery(phrase);
        String sql = String.format(
                "select @rid, yago_label.length() as length, lucene_score as score from(" + "\n"
                + "select expand(in) from (" + "\n"
                 +"     select from ("       + "\n"
                  +              "select expand(inE()) from (" + "\n"
                   +                     "select *,$score as lucene_score" + "\n"
                   +                     "from YAGO_LABEL_CLASS" + "\n"
                   +                     "where yago_label LUCENE \"%s\"" + "\n"
                   +            ")" + "\n"
                    +    ")"  + "\n"
                    +    "where yago_label = 'rdfs:label'" + "\n"
                    +") order by lucene_score desc"  + "\n"
                   +")"  + "\n"
                , query
        );

        logger.info("[getLuceneSortedResultForEntity] sql = \n{}" , sql);
        Iterable<Vertex> vertices = (Iterable<Vertex>) this.orientGraph.command(
                new OCommandSQL(sql )
        ).execute();

        Map<String, LuceneItem> lucene_scores = new HashMap<>();
        for(Vertex row: vertices){
            String rid = YagoQueryHelper.getRidOfVertex( row.getProperty("rid") );
            lucene_scores.put( rid, new LuceneItem(rid,row.getProperty("score"),row.getProperty("length") ));
        }

        return lucene_scores;
    }

}
